Skip to content

feat: Add Zvec in-process vector database for semantic code search#5245

Open
oldschoola wants to merge 5 commits into
can1357:mainfrom
oldschoola:feat/zvec-code-search
Open

feat: Add Zvec in-process vector database for semantic code search#5245
oldschoola wants to merge 5 commits into
can1357:mainfrom
oldschoola:feat/zvec-code-search

Conversation

@oldschoola

@oldschoola oldschoola commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Add native support for Zvec (Alibaba's in-process vector database) as a semantic code search backend. No MCP server or external daemon — runs entirely in-process, just like the existing SQLite-based mnemopi memory engine.

Opt-in by design: Code search is disabled by default. Users enable it via /settings → Tools → Available Tools → Code Search (Zvec), then explicitly build the index with /code-index. The code_search tool does not auto-index — it only searches the existing index and tells users to run /code-index when the index is empty.

Architecture

coding-agent
 ├── /code-index slash command ──→ indexWorkspace()
 │    └── uses loadMnemopi() for lazy module loading
 │
 └── code_search tool (discoverable, gated by tools.codeSearchEnabled)
      ├── workspace scanner (gitignore-aware)
      ├── code chunker (100-line chunks, 10-line overlap)
      ├── embedding via mnemopi's embed()/embedQuery()
      └── ZVecCodeStore (from pi-mnemopi)
           ├── HNSW vector index (cosine)
           ├── BM25 full-text index
           └── hybrid search (RRF fusion)

Changes

mnemopi package (@oh-my-pi/pi-mnemopi)

  • zvec-store.ts: ZVecCodeStore class — Zvec vector store wrapper with upsert, vector search (HNSW), FTS search (BM25), hybrid search (RRF), removeFile (via deleteByFilterSync), getFileHashes, optimize
  • zvec-config.ts: Config functions (OMP_ZVEC_* env vars for index path, chunk size, overlap, top-K)
  • @zvec/zvec added as optional peer dependency

coding-agent package (@oh-my-pi/pi-coding-agent)

  • settings-schema.ts: Added tools.codeSearchEnabled setting (default: false) under Tools → Available Tools
  • builtin-registry.ts: Added /code-index slash command — explicitly builds or rebuilds the Zvec code search index; uses loadMnemopi() for lazy module loading
  • code-search-index.ts: Standalone indexWorkspace() function — shared by both the slash command and the tool; uses loadMnemopi() to keep mnemopi off the startup module graph
  • code-search-helpers.ts: Shared helpers (chunking, language detection, binary detection, file filtering)
  • code-search.ts: CodeSearchTool — searches the existing index only (no auto-indexing); hybrid vector+FTS search with FTS-only fallback; overfetches when a glob pattern filter is provided
  • code-search.md: Tool description prompt (mentions /code-index requirement)
  • Tool registered as discoverable (loadMode=discoverable), only loads when needed
  • createIf returns null when tools.codeSearchEnabled is false or @zvec/zvec native addon not loadable

Infrastructure

  • @zvec/zvec: 0.5.0 added to workspace catalog
  • trustedDependencies: ["@zvec/zvec"] added to root package.json (Bun lifecycle script allowlist)

Key design decisions

  • Opt-in, not default: tools.codeSearchEnabled defaults to false. Users must explicitly enable it in settings and run /code-index to build the index. The tool does not auto-index on first search.
  • Embedding source: Uses mnemopi's existing embed()/embedQuery() pipeline (local fastembed via ONNX or API-based). Does NOT use pi-ai (no embedding client) or Zvec's Python-only embedding functions.
  • Fallback strategy: When embeddings are unavailable, falls back to BM25-only FTS search — not a grep duplicate (ranked chunks across workspace vs individual matching lines).
  • Incremental indexing: Compares persisted chunk hashes via getFileHashes() to skip unchanged files across sessions. removeFile uses deleteByFilterSync for O(1) cleanup. Files that grow past 1MB or become binary have their stale chunks removed automatically.
  • Chunk ID format: Uses ${Bun.hash(filePath + "\\0" + content)}-${lineStart} — includes file path to prevent duplicate-content collisions; Zvec rejects :, /, | in document IDs.
  • Lazy module loading: The /code-index slash command and indexWorkspace() use loadMnemopi() from src/mnemopi/state.ts (memoized lazy loader) instead of raw await import(), respecting onnxruntime-node NAPI load-ordering constraints.

Verification

  • Smoke test: Real ZVecCreateAndOpen → insert → optimize → vector query → FTS query → hybrid multiQuery → removeFile → close — all pass under Bun
  • mnemopi tests: 14 pass, 0 fail
  • coding-agent tests: 2 pass, 0 fail (edit-then-reindex correctness — no stale chunks)
  • Type checks: Both packages pass bun run check:types
  • Biome: Clean on all new/modified files

Review fixes addressed

  • Doc-ID collision: Include file path in chunk hash (Bun.hash(filePath + "\\0" + content)) so duplicate files don't overwrite each other
  • Stale chunks on skip: Move currentFiles.add() after size/binary checks; call store.removeFile() when a previously-indexed file becomes too large or binary
  • Pattern filter reliability: Overfetch (topK*5, min 100) when a glob pattern is provided, then slice to topK after filtering
  • Test env safety: Pass local env object to config helpers instead of mutating process.env

Test plan

  • cd packages/mnemopi && bun test test/zvec-store.test.ts — 14 tests
  • cd packages/coding-agent && bun test src/tools/__tests__/code-search-index.test.ts — 2 tests
  • cd packages/mnemopi && bun run check:types
  • cd packages/coding-agent && bun run check:types

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

@github-actions github-actions Bot added the vouched Passed the vouch gate label Jul 11, 2026
@roboomp roboomp added agent Agent runtime planning and orchestration feat review:p2 tool Tool behavior and integrations triaged labels Jul 11, 2026

@roboomp roboomp left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

review:p2 — coherent feature, but it is a new default-enabled native-backed code-search path and needs maintainer sign-off.
Blocking findings: duplicate file contents collide on Zvec document IDs, and stale chunks remain when an indexed file later becomes too large/binary. Also flagged unreliable post-topK pattern filtering and a full-suite-safety issue in the env override test.
Verification: bun test test/zvec-store.test.ts, bun test src/tools/__tests__/code-search-index.test.ts, and both package bun run check:types commands pass; a focused duplicate-ID repro shows Zvec stores only one doc for two same-ID chunks.
Thanks for the substantial implementation and the targeted smoke coverage.

Comment thread packages/coding-agent/src/tools/code-search.ts Outdated
Comment thread packages/coding-agent/src/tools/code-search.ts Outdated
Comment thread packages/coding-agent/src/tools/code-search.ts
Comment thread packages/mnemopi/test/zvec-store.test.ts Outdated
…search

Add native support for Zvec (@zvec/zvec), Alibaba's in-process vector
database, as a code search backend. No MCP server or external daemon
required — runs entirely in-process like the existing SQLite memory engine.

mnemopi package:
- ZVecCodeStore: vector store wrapper with HNSW vector search, BM25
  full-text search, and hybrid (RRF) search for code chunks
- zvec-config: environment-configurable settings (OMP_ZVEC_* env vars)
- @zvec/zvec added as optional peer dependency

coding-agent package:
- code_search tool: workspace indexing with gitignore-aware scanning,
  100-line chunking with 10-line overlap, embedding via mnemopi's
  embed()/embedQuery(), hybrid vector+FTS search with FTS-only fallback
- Discoverable tool (loadMode=discoverable), only loads when needed
- Incremental indexing: compares persisted chunk hashes to skip unchanged
  files across sessions; removeFile uses deleteByFilterSync for O(1) cleanup

Verified with real @zvec/zvec native addon under Bun: create, upsert,
vector search, FTS search, hybrid multiQuery, removeFile, close.
14 mnemopi tests + 2 coding-agent index tests pass, 0 fail.
- Add tools.codeSearchEnabled setting (default: false) to settings schema
  under Tools → Available Tools; code_search tool is now gated by this
  setting instead of the OMP_ZVEC_ENABLED env var
- Add /code-index slash command to explicitly build or rebuild the Zvec
  code search index; uses loadMnemopi() for lazy module loading
- Refactor indexing logic into standalone indexWorkspace() function in
  code-search-index.ts, shared by both the slash command and the tool
- Tool no longer auto-indexes on first search; only searches the existing
  index and tells users to run /code-index when the index is empty
- Update tool description to mention /code-index requirement
- Fix doc-ID collision: include file path in chunk hash
  (Bun.hash(filePath + "\0" + content)) so duplicate files don't
  overwrite each other in the Zvec index
- Fix stale chunks: move currentFiles.add() after size/binary checks;
  call store.removeFile() when a previously-indexed file becomes too
  large or binary
- Fix pattern filter: overfetch (topK*5, min 100) when a glob pattern
  is provided, then slice to topK after filtering
- Fix test env safety: pass local env object to config helpers instead
  of mutating process.env
- Sort imports and fix formatting in all new files (Biome)
- Remove unused private session field in CodeSearchTool
- Rename unused signal parameter to _signal in #search()
@oldschoola oldschoola force-pushed the feat/zvec-code-search branch from 460ed58 to e750bc3 Compare July 12, 2026 01:08
Zvec upsert/optimize/searchFts calls are synchronous but slow on CI
hardware. Both tests exceeded the 5s default timeout (6.7s and 7.1s).
Set describe-level testTimeout to 15s.
@oldschoola oldschoola force-pushed the feat/zvec-code-search branch from e750bc3 to ff0d865 Compare July 12, 2026 01:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent Agent runtime planning and orchestration feat review:p2 tool Tool behavior and integrations triaged vouched Passed the vouch gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants